/*
 * $Id: stdlib.h 142 2011-10-28 07:39:36Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#ifndef _XP_BAS_STDLIB_H_
#define _XP_BAS_STDLIB_H_

#include <xp/types.h>
#include <xp/macros.h>
#include <xp/bas/assert.h>

#include <stdlib.h>

#define XP_EXIT_SUCCESS EXIT_SUCCESS
#define XP_EXIT_FAILURE EXIT_FAILURE

/* definition for rc4 functions */
#define XP_RC4_MAX_PASSWD 256
struct xp_rc4_t
{
	xp_byte_t passwd[XP_RC4_MAX_PASSWD];
	xp_size_t passwd_len;

	int sbox[256];
	int key[256];
	int idxa;
	int idxb;

	xp_bool_t __dynamic;
};
typedef struct xp_rc4_t xp_rc4_t;

/* definition for md5 functions */
struct xp_md5_t
{
	xp_uint32_t count[2];
	xp_uint32_t state[4];
	xp_byte_t   buffer[64];
	xp_bool_t   __dynamic;
};
typedef struct xp_md5_t xp_md5_t;

/* definition for blowfish functions */
#define XP_BLOWFISH_NUM_SUBKEYS 18
#define XP_BLOWFISH_NUM_S_BOXES 4
#define XP_BLOWFISH_NUM_ENTRIES 256
#define XP_BLOWFISH_MAX_KEY_LEN 56
struct xp_blowfish_t
{
	xp_uint32_t PA[XP_BLOWFISH_NUM_SUBKEYS];
	xp_uint32_t SB[XP_BLOWFISH_NUM_S_BOXES][XP_BLOWFISH_NUM_ENTRIES];
	xp_bool_t   __dynamic;
};
typedef struct xp_blowfish_t xp_blowfish_t;

#ifdef __cplusplus
extern "C" {
#endif

#define xp_exit exit 
#define xp_abort abort 

/* 
 * FUNCTION: xp_bitcount 
 */
int xp_bitcount (void* num, xp_size_t size);

int xp_digtoi (xp_char_t c, int base);

xp_size_t xp_bytetostr_upper (xp_byte_t byte, 
	xp_char_t* buf, xp_size_t size, int base, xp_char_t fill);
xp_size_t xp_bytetostr_lower (xp_byte_t byte,
	xp_char_t* buf, xp_size_t size, int base, xp_char_t fill);

xp_size_t xp_uint16tostr_lower (
        xp_uint16_t value, xp_char_t* buf, xp_size_t size, int base, xp_char_t fill);
xp_size_t xp_uint16tostr_lower (
        xp_uint16_t value, xp_char_t* buf, xp_size_t size, int base, xp_char_t fill);


int xp_atoi (const xp_char_t* str);
long xp_atol (const xp_char_t* str);

xp_int_t xp_strtoint (const xp_char_t* str);
xp_long_t xp_strtolong (const xp_char_t* str);
xp_uint_t xp_strtouint (const xp_char_t* str);
xp_ulong_t xp_strtoulong (const xp_char_t* str);
xp_real_t xp_strtoreal (const xp_char_t* str);

xp_size_t xp_inttostr (xp_int_t num, int base, xp_char_t* buf);
xp_size_t xp_longtostr (xp_long_t num, int base, xp_char_t* buf);
xp_size_t xp_uinttostr (xp_uint_t num, int base, xp_char_t* buf);
xp_size_t xp_ulongtostr (xp_ulong_t num, int base, xp_char_t* buf);
xp_size_t xp_sizetostr (xp_size_t num, int base, xp_char_t* buf);

/* rc4 functions */
xp_rc4_t* xp_rc4_open (xp_rc4_t* rc4);
void xp_rc4_close (xp_rc4_t* rc4);
void xp_rc4_set_passwd (xp_rc4_t* rc4, const void* pw, xp_size_t psz);
void xp_rc4_restart (xp_rc4_t* rc4);
xp_byte_t xp_rc4_cipher (xp_rc4_t* rc4, xp_byte_t c);

/* stand-alone rc4 function */
xp_size_t xp_cipherrc4 (
	const void* src, xp_size_t ssz,
	void* dst, xp_size_t dsz, 
	const void* pw, xp_size_t pwlen);

/* base-64 functions */
xp_size_t xp_encodebase64 (
	const xp_byte_t* in, xp_size_t isz, 
	xp_byte_t* out, xp_size_t osz, xp_size_t* xsz);
xp_size_t xp_decodebase64 (
	const xp_byte_t* in, xp_size_t isz,
	xp_byte_t* out, xp_size_t osz, xp_size_t* xsz);

/* md5 functions */
xp_md5_t* xp_md5_open (xp_md5_t* md5);
void xp_md5_close (xp_md5_t* md5);
void xp_md5_update (xp_md5_t* md5, const void* data, xp_uint32_t len);
xp_size_t xp_md5_digest (xp_md5_t* md5, void* digest, xp_size_t size);

/* blowfish functions */
xp_blowfish_t* xp_blowfish_open (xp_blowfish_t* bf);
void xp_blowfish_close (xp_blowfish_t* bf);
void xp_blowfish_setkey (xp_blowfish_t* bf, const void* key, xp_size_t len);
int xp_blowfish_encrypt (xp_blowfish_t* bf, void *data, xp_size_t len);
int xp_blowfish_decrypt (xp_blowfish_t* bf, void *data, xp_size_t len);

#ifdef __cplusplus
}
#endif

/* xp_strtoi (const xp_char_t* nptr, xp_char_t** endptr, int base) */
#define XP_STRTOI(value,nptr,endptr,base) \
	{ \
		int __strtoi_f = 0, __strtoi_v; \
		const xp_char_t* __strtoi_ptr = nptr; \
		for (;;) { \
			xp_char_t __strtoi_c = *__strtoi_ptr; \
			if (__strtoi_c == XP_CHAR(' ') || \
			    __strtoi_c == XP_CHAR('\t')) { __strtoi_ptr++; continue; } \
			if (__strtoi_c == XP_CHAR('-')) { __strtoi_f++; __strtoi_ptr++; } \
			if (__strtoi_c == XP_CHAR('+')) { __strtoi_ptr++; } \
			break; \
		} \
		for (value = 0; (__strtoi_v = xp_digtoi(*__strtoi_ptr, base)) < base; __strtoi_ptr++) { \
			value = value * base + __strtoi_v; \
		} \
		if (endptr != XP_NULL) *((const xp_char_t**)endptr) = __strtoi_ptr; \
		if (__strtoi_f > 0) value *= -1; \
	}

/* xp_strxtoi (const xp_char_t* nptr, xp_size_t len, xp_char_char** endptr, int base) */
#define XP_STRXTOI(value,nptr,len,endptr,base) \
	{ \
		int __strtoi_f = 0, __strtoi_v; \
		const xp_char_t* __strtoi_ptr = nptr; \
		const xp_char_t* __strtoi_end = __strtoi_ptr + len; \
		value = 0; \
		while (__strtoi_ptr < __strtoi_end) { \
			xp_char_t __strtoi_c = *__strtoi_ptr; \
			if (__strtoi_c == XP_CHAR(' ') || __strtoi_c == XP_CHAR('\t')) { \
				__strtoi_ptr++; continue; \
			} \
			if (__strtoi_c == XP_CHAR('-')) { __strtoi_f++; __strtoi_ptr++; } \
			if (__strtoi_c == XP_CHAR('+')) { __strtoi_ptr++; } \
			break; \
		} \
		for (value = 0; __strtoi_ptr < __strtoi_end && \
		                (__strtoi_v = xp_digtoi(*__strtoi_ptr, base)) != base; __strtoi_ptr++) { \
			value = value * base + __strtoi_v; \
		} \
		if (endptr != XP_NULL) *((const xp_char_t**)endptr) = __strtoi_ptr; \
		if (__strtoi_f > 0) value *= -1; \
	}

#define XP_ITOSTR(type,value,base,buf,outlen) \
do { \
	type _itostr_last = value % base; \
	type _itostr_y = 0, _itostr_dig = 0; \
	xp_char_t* _itostr_p = buf; \
\
	XP_ASSERT (base >= 2 && base <= 36); \
	if (value < 0) *_itostr_p++ = XP_T('-'); \
	value = value / base; \
	if (value < 0) value = -value; \
\
	while (value > 0) \
	{ \
		_itostr_y = _itostr_y * base + (value % base); \
		value /= base; _itostr_dig++; \
	} \
\
	while (_itostr_y > 0) \
	{ \
		type _itostr_t = _itostr_y % base; \
		if (_itostr_t >= 0 && _itostr_t <= 9) \
			*_itostr_p++ = _itostr_t + XP_T('0'); \
		else *_itostr_p++ = (_itostr_t - 10) + XP_T('A'); \
		_itostr_y /= base; _itostr_dig--; \
	} \
\
	while (_itostr_dig > 0) { _itostr_dig--; *_itostr_p++ = XP_T('0'); } \
	if (_itostr_last < 0) _itostr_last = -_itostr_last; \
	if (_itostr_last >= 0 && _itostr_last <= 9) \
		*_itostr_p++ = _itostr_last + XP_T('0'); \
	else *_itostr_p++ = (_itostr_last - 10) + XP_T('A'); \
	*_itostr_p = XP_T('\0'); \
	if (outlen != XP_NULL) *outlen = _itostr_p - buf; \
} while (0);

#if 0
#define XP_ITOSTRX(type,value,buf,len) \
do { \
	type _itostrx_last = value % 10; \
	type _itostrx_y = 0, _itostrx_dig = 0; \
	xp_char_t* _itostrx_p = buf; \
	xp_char_t* _itostrx_end = buf + len; \
\
	if (value < 0) *_itostrx_p++ = XP_T('-'); \
	value = value / 10; \
	if (value < 0) value = -value; \
\
	while (value > 0) \
	{ \
		_itostrx_y = _itostrx_y * 10 + (value % 10); \
		value /= 10; _itostrx_dig++; \
	} \
\
	while (_itostrx_y > 0) \
	{ \
		*_itostrx_p++ = ((_itostrx_y % 10) + XP_T('0')); \
		_itostrx_y /= 10; _itostrx_dig--; \
	} \
\
	while (_itostrx_dig > 0) { _itostrx_dig--; *_itostrx_p++ = XP_T('0'); } \
	if (_itostrx_last < 0) _itostrx_last = -_itostrx_last; \
	*_itostrx_p++ = (_itostrx_last + XP_T('0')); \
	*_itostrx_p = XP_T('\0'); \
	if (outlen != XP_NULL) *outlen = _itostr_p - buf; \
} while (0);
#endif

#endif
